package com.zhijian.medical.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.zhijian.medical.config.Constants;
import com.zhijian.medical.dao.local.ProductMapper;
import com.zhijian.medical.entity.UploadParam;
import com.zhijian.medical.entity.dto.PersonDto;
import com.zhijian.medical.entity.po.*;
import com.zhijian.medical.entity.vo.request.ProductSearchVo;
import com.zhijian.medical.entity.vo.request.ProductSendOutDetailBatchSearchVo;
import com.zhijian.medical.entity.vo.request.ProductSendOutVo;
import com.zhijian.medical.entity.vo.response.ProductVo;
import com.zhijian.medical.enums.*;
import com.zhijian.medical.exception.BusinessException;
import com.zhijian.medical.service.*;
import com.zhijian.medical.util.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 产品表业务处理层
 *
 * @author HCG
 * @version: 1.0
 * @date 2022-01-17 14:55:39
 */
@Slf4j
@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductMapper mapper;

    @Autowired
    private PersonService personService;

    @Autowired
    private AgentiaCategoryService agentiaCategoryService;

    @Autowired
    private AgentiaService agentiaService;

    @Autowired
    private PersonGroupService personGroupService;

    @Autowired
    private ProductSendOutDetailService productSendOutDetailService;

    @Autowired
    private ProductSendOutDetailBatchService productSendOutDetailBatchService;

    @Autowired
    private UploadParam uploadParam;

    /**
     * 前端页面地址前缀
     */
    @Value("${qr.urlPrefix}")
    private String qrUrlPrefix;

    @Override
    public Product selectById(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public ProductVo selectVoById(Long id) {
        return mapper.selectVoById(id);
    }

    @Override
    public void deleteById(Long id) {
        mapper.deleteByPrimaryKey(id);
    }

    @Override
    public void deleteByIdAndPersonId(Long id, Long personId) {
        Product product = this.selectById(id);
        if (Objects.isNull(product)) {
            throw new BusinessException(ResponseCodeEnum.FAILURE.code, "此产品不存在或者已被删除");
        }
        if (!Objects.equals(product.getApplyUserId(), personId)) {
            throw new BusinessException(ResponseCodeEnum.FAILURE.code, "只能由申请人进行删除");
        }
        this.deleteById(id);
    }

    @Override
    public Long insert(Product product) {
        Date now = new Date();
        product.setCreateTime(now);
        product.setUpdateTime(now);
        //默认等待审批状态
        product.setStatus(ProductTurnStatusEnum.SHEN_QING.getCode().byteValue());
        //默认设备试剂管理员
        product.setApproveUserName(ApproveRoleNameEnum.SBSJGLY.getDesc());
        //查出试剂品类名称
        AgentiaCategory agentiaCategory = agentiaCategoryService.selectById(product.getAgentiaCategoryId());
        if (Objects.isNull(agentiaCategory)) {
            throw new BusinessException(ResponseCodeEnum.FAILURE.code, "此试剂品类不存在或者已被删除");
        }
        product.setName(agentiaCategory.getName());
        //生成申购码
        product.setCode(String.format("SG%s%s", System.currentTimeMillis(), RandomUtil.randomString(4)));
        return mapper.insert(product) > 0 ? product.getId() : 0L;
    }

    @Override
    public boolean update(Product product) {
        Date now = new Date();
        product.setUpdateTime(now);
        return mapper.updateByPrimaryKey(product) != 0;
    }

    @Override
    public boolean updateByPrimaryKeySelective(Product record) {
        return mapper.updateByPrimaryKeySelective(record) != 0;
    }

    @Override
    public Integer count(ProductSearchVo productSearchVo) {
        return mapper.count(productSearchVo);
    }

    @Override
    public List<ProductVo> selectList(ProductSearchVo productSearchVo) {
        return mapper.selectList(productSearchVo);
    }

    @Override
    public Page<ProductVo> selectPage(ProductSearchVo productSearchVo) {
        //先直接查总数
        int count = count(productSearchVo);
        //分页
        Page<ProductVo> page = new Page<>(true, count, productSearchVo.getPageNum(), productSearchVo.getPageSize());
        productSearchVo.setStartIndex(page.getStartIndex());
        page.setPage(true);
        page.setTotalCount(count);
        List<ProductVo> responseVos = this.selectList(productSearchVo);
        page.setData(responseVos);
        return page;
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public boolean approve(Long id) {
        Product product = this.selectById(id);
        if (Objects.isNull(product)) {
            throw new BusinessException(ResponseCodeEnum.FAILURE.code, "此产品不存在或者已被删除");
        }
        Byte status = product.getStatus();
        if (Objects.isNull(status)) {
            throw new BusinessException(ResponseCodeEnum.FAILURE.code, "此产品状态异常");
        }
        ProductTurnStatusEnum productTurnStatusEnum = ProductTurnStatusEnum.getByCode(status.intValue());
        if (Objects.isNull(productTurnStatusEnum)) {
            throw new BusinessException(ResponseCodeEnum.FAILURE.code, "此产品状态异常");
        }
        switch (productTurnStatusEnum) {
            case SHEN_QING:
                //处于刚申请状态，要修改成设备试剂管理员审批通过，亚专科主任待审批状态
                //modify 2022-04-25 现在亚专科主任审批也去掉了
                mapper.updateByPrimaryKeySelective(Product.builder()
                        .id(id)
                        .status(ProductTurnStatusEnum.APPROVED.getCode().byteValue())
                        //审批结束
                        .approveUserName(ApproveRoleNameEnum.OVER.getDesc())
                        .updateTime(new Date())
                        .build());
                break;
            case SEND_OUT:
                //处于厂家发货状态，要修改成确认收货状态
                mapper.updateByPrimaryKeySelective(Product.builder()
                        .id(id)
                        .status(ProductTurnStatusEnum.HARVEST.getCode().byteValue())
                        .updateTime(new Date())
                        .build());
                //查询申请人的组
                List<Long> groupIds = personGroupService.selectGroupIdsByPersonId(Objects.nonNull(product.getApplyUserId()) ? product.getApplyUserId() : 0);
                //入库试剂，新增一条记录
                agentiaService.insert(Agentia.builder()
                        .name(product.getName())
                        .number(product.getNumber())
                        .batchNumber(product.getNumber())
                        .stock(product.getQuantity())
                        .brand(product.getBrand())
                        .categoryId(product.getAgentiaCategoryId())
                        .groupId(!org.apache.commons.collections4.CollectionUtils.isEmpty(groupIds) ? groupIds.get(0) : null)
                        .storageDate(DateUtil.formatDate(new Date()))
                        .build()
                );
                break;
            case HARVEST:
                throw new BusinessException(ResponseCodeEnum.FAILURE.code, "此产品已经确认收货");
            default:
                break;
        }
        return false;
    }

    @Override
    public boolean cancel(Long id) {
        Product product = this.selectById(id);
        if (Objects.isNull(product)) {
            throw new BusinessException(ResponseCodeEnum.FAILURE.code, "此产品不存在或者已被删除");
        }
        return mapper.updateByPrimaryKeySelective(Product.builder()
                .id(id)
                .status(ProductTurnStatusEnum.CANCEL.getCode().byteValue())
                .updateTime(new Date())
                .build()) > 0;
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public boolean sendOut(ProductSendOutVo productSendOutVo, boolean isApplyUser) {
        ProductVo productVo = this.selectVoById(productSendOutVo.getProductId());
        if (Objects.isNull(productVo)) {
            throw new BusinessException(ResponseCodeEnum.FAILURE.code, "此产品不存在或者已被删除");
        }
        if (productVo.getStatus() != ProductTurnStatusEnum.APPROVED.getCode().byteValue()
                && productVo.getStatus() != ProductTurnStatusEnum.SEND_OUT.getCode().byteValue()) {
            throw new BusinessException(ResponseCodeEnum.FAILURE.code, "此产品状态不允许发货");
        }
        //生成发货码
        String fhCode = String.format("FH%s%s", System.currentTimeMillis(), RandomUtil.randomString(4));
        //文件储存路径
        String storePath = uploadParam.getStorePath();
        // 生成指定url对应的二维码到文件，宽和高都是300像素
        String realPath = String.format("%s%s.jpg", storePath, fhCode);
        //二维码的内容
        String qrContent = String.format("%s%s?code=%s", qrUrlPrefix, Constants.QR_URL_PATH_END, fhCode);
        log.info("二维码内容：{}", qrContent);
        QrCodeUtil.generate(qrContent, 300, 300, FileUtil.file(realPath));
        //补充具体字段，生成二维码
        Long productSendOutDetailId = productSendOutDetailService.insert(ProductSendOutDetail.builder()
                //生成发货码
                .code(fhCode)
                .productId(productVo.getId())
                .name(productSendOutVo.getName())
                //如果是申请人员操作，直接已完成
                .status(isApplyUser ? ProductSendOutDetailStatusEnum.ALREADY_HARVEST.getCode().byteValue() : ProductSendOutDetailStatusEnum.UN_HARVEST.getCode().byteValue())
                .deliverAddress(productSendOutVo.getDeliverAddress())
                .receiveUserPhone(productSendOutVo.getReceiveUserPhone())
                .receiveUser(productSendOutVo.getReceiveUser())
                //二维码地址
                .qrFilePath(String.format("%s%s", uploadParam.getUrlPath(), String.format("%s.jpg", fhCode)))
                .build());

        //循环存入这次发货的批次号、数量
        //这里也要生成二维码
        productSendOutVo.getBatchList().forEach(batchVo -> {
                    if (!isApplyUser && Objects.isNull(batchVo.getMonitorModuleId())) {
                        throw new BusinessException(ResponseCodeEnum.FAILURE.code, "监测模块id不能为空");
                    }
                    //批次号
                    String batchNumber = batchVo.getBatchNumber();
                    Integer count = productSendOutDetailBatchService.count(ProductSendOutDetailBatchSearchVo.builder()
                            .detailId(productSendOutDetailId)
                            .batchNumber(batchNumber)
                            .build());
                    if (count > 0) {
                        throw new BusinessException(ResponseCodeEnum.FAILURE.code, "有重复批次号，请重新输入");
                    }
                    //拼接出二维码文件名称，发货号+批次号
                    String fileName = String.format("%s%s", fhCode, batchNumber);
                    //二维码文件地址
                    String detailBatchRealPath = String.format("%s%s.jpg", storePath, fileName);
                    QrCodeUtil.generate(batchNumber, 300, 300, FileUtil.file(detailBatchRealPath));
                    productSendOutDetailBatchService.insert(ProductSendOutDetailBatch.builder()
                            .detailId(productSendOutDetailId)
                            .productId(productVo.getId())
                            .batchNumber(batchNumber)
                            .quantity(batchVo.getQuantity())
                            .produceDate(DateUtil.parseDate(batchVo.getProduceDate()))
                            .effective(batchVo.getEffective())
                            .qrFilePath(String.format("%s%s", uploadParam.getUrlPath(), String.format("%s.jpg", fileName)))
                            .weatherIsLargess(batchVo.getWeatherIsLargess())
                            .monitorModuleId(batchVo.getMonitorModuleId())
                            .build());
                }
        );
        return mapper.updateByPrimaryKeySelective(Product.builder()
                .id(productSendOutVo.getProductId())
                //如果是医院自己发货，就汇总出所有已发货的数目，发货数目足够了，就改成已完成，否则就还是发货中
                .status(isApplyUser && productSendOutDetailBatchService.sumQuantityByProductId(productVo.getId()) >= productVo.getQuantity() ? ProductTurnStatusEnum.HARVEST.getCode().byteValue() : ProductTurnStatusEnum.SEND_OUT.getCode().byteValue())
                .updateTime(new Date())
                .build()) > 0;
    }

    @Override
    public boolean applyUserHarvest(ProductSendOutVo productSendOutVo) {
        return sendOut(productSendOutVo, true);
    }

    @Override
    public ProductSearchVo checkRoleParam(PersonDto personDto, ProductSearchVo productSearchVo) {
        //登录用户的角色id集合
        List<Long> roleIds = personDto.getRoleIds();
        if (!CollectionUtils.isEmpty(roleIds)) {
            if (!CollectionUtils.isEmpty(CollectionUtils.intersection(roleIds, RoleNewEnum.XING_ZHENG_ZHU_REN.getCodes()))) {
                //行政主任看所有的，直接返回
                return productSearchVo;
            }
            if (!CollectionUtils.isEmpty(CollectionUtils.intersection(roleIds, RoleNewEnum.GONG_YING_SHANG.getCodes()))) {
                //如果是厂家人员的话，只看跟自己厂关联的
                productSearchVo.setFactoryId(personDto.getCooperativeInstitutionId());
                return productSearchVo;
            }
            if (!CollectionUtils.isEmpty(CollectionUtils.intersection(roleIds, RoleNewEnum.SQKZ_RY.getCodes()))) {
                //如果是申请人员的话，只看跟自己关联的
                productSearchVo.setApplyUserId(personDto.getId());
                return productSearchVo;
            }
            if (!CollectionUtils.isEmpty(CollectionUtils.intersection(roleIds, RoleNewEnum.FIRST_APPROVE.getCodes()))
                    || !CollectionUtils.isEmpty(CollectionUtils.intersection(roleIds, RoleNewEnum.SECOND_APPROVE.getCodes()))) {
                //如果是第一步审批人员或者第二步审批人员的话，只看自己组的数据
                productSearchVo.setGroupIds(personDto.getGroupIds());
                return productSearchVo;
            }
        } else {
            productSearchVo.setApplyUserId(0L);
        }
        return productSearchVo;
    }

}